﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;
using Kobets.Automation.Chimera.Common;
using Kobets.Automation.Chimera.Orchestrator.Models;
using Kobets.Automation.Chimera.Orchestrator.Shared;

namespace Kobets.Automation.Chimera.Orchestrator.Controllers
{
    [LogActionFilter]
    public class ExecuteController : Controller
    {
        public ActionResult Index(string error)
        {
            ViewBag.Error = String.IsNullOrWhiteSpace(error) ? "" : error;
            ViewBag.Title = "Execute";
            var agents = Shared.Common.GetAgentsList();
            var groups = agents.Where(a => !String.IsNullOrWhiteSpace(a.Group)).Select(g => g.Group).Distinct().Select(o => new EnchancedSelectListItem { Text = o, Value = o, Disabled = agents.Where(g => g.Group == o).Any(a => a.Status == Enums.AgentStatus.Running || a.Status == Enums.AgentStatus.Disconnected) }).ToList();
            var dStyles = (from Enums.DistributionStyle style in Enum.GetValues(typeof(Enums.DistributionStyle)) select new SelectListItem { Text = style.ToString(), Value = style.ToString(), Selected = (style == Enums.DistributionStyle.Even) }).ToList();

            var db = new Models.ProfilesEntities();
            var tpDb = new Models.TestPackagesEntities();
            
            ViewBag.Agents = agents;
            ViewBag.Group = groups;
            ViewBag.InitialSelectedGroup = groups.FindIndex(i => !i.Disabled);
            ViewBag.Distribution = dStyles;
            ViewBag.ExecutionPackage = tpDb.TestPackages.ToList().Select(tp => new SelectListItem { Text = tp.Name, Value = tp.pId.ToString(CultureInfo.InvariantCulture) }).ToList();

            return View(db.Profiles.Where(w => w.Enabled).ToList().OrderBy(s => s.ProfileName));
        }

        [HttpPost]
        public ActionResult Execute(string executionPackage, string group, string distribution, bool enableSLM = false, string dxVersion = "")
        {
            if (Shared.Common.GetAgentsList().Where(g => g.Group == @group).Any(agent => agent.Status == Enums.AgentStatus.Running))
                return RedirectToAction("Index", "Execute", new { error = "Error: Unable to execute run for non-idle group" });

            var form = HttpContext.Request.Form;
            var selectedProfiles = new List<int>();
            
            if (form != null && form.Count > 0)
            {
                for (var i = 0; i < form.Keys.Count; i++)
                {
                    if (form.Keys[i].Contains("chk_") && form[i].Contains("true"))
                        selectedProfiles.Add(Int16.Parse(form.Keys[i].Remove(0, 4)));
                }
            }

            if (selectedProfiles.Count == 0)
                return RedirectToAction("Index", "Execute", new { error = "Error: Must select at least one runtime" });

            var tpDb = new Models.TestPackagesEntities();
            var pDb = new Models.ProfilesEntities();
            var testCases = new List<TestCase>();
            var testPackage = tpDb.TestPackages.ToList().Find(tp => tp.pId == int.Parse(executionPackage));

            foreach (var profileId in selectedProfiles)
            {
                var profile = pDb.Profiles.ToList().Find(pid => pid.ProfileID == profileId);

                if (profile.IsSprint && String.IsNullOrWhiteSpace(dxVersion))
                    return RedirectToAction("Index", "Execute", new { error = "Error: You have chosen Sprint or SX+ profile/s. Please select appropriate DX/SX+ version to install." });

                var p = new Profile
                            {
                                Name = profile.ProfileName,
                                Serial = profile.Serial,
                                Folder = profile.Folder,
                                IsPATest = profile.IsPATest,
                                IsPostPublish = profile.IsPostPublish,
                                IsSingleVendor = profile.IsSingleVendor,
                                Password = profile.Password,
                                Priority = (profile.Priority.HasValue) ? profile.Priority.Value : 0,
                                Username = profile.Username,
                                Weight = (profile.Weight.HasValue) ? profile.Weight.Value : 0,
                                DXVersion = dxVersion,
                                SMXRuntimeName = profile.SMXRuntimeName
                            };

                if (profile.IsSprint)
                    p.ProfileType = Enums.ProfileType.Sprint;
                else if (profile.IsSXP)
                    p.ProfileType = Enums.ProfileType.SXP;
                else
                    p.ProfileType = Enums.ProfileType.DX;

                testCases.AddRange(pDb.AllCasesView.ToList().FindAll(tc => tc.ProfileName == profile.ProfileName)
                    .Select(testcase => new TestCase
                                            {
                                                Profile = p, 
                                                AdvisorName = testcase.AdvisorName, 
                                                ProjectFileName = testcase.ProjectFileName,
                                                Attributes = CommonMethods.TextToAttributes(testPackage.Attributes)
                                            }));
            }

            if (testCases.Count > 0)
                Shared.Common.ExecuteRun(testPackage, (Enums.DistributionStyle)Enum.Parse(typeof(Enums.DistributionStyle), distribution), @group, testCases.ToArray(), HttpContext.User.Identity.Name, enableSLM);

            return RedirectToAction("Index", "Home", new { Group = @group });
        }
        
        [HttpGet]
        public PartialViewResult Refresh()
        {
            var agents = Shared.Common.GetAgentsList();
            ViewBag.Agents = agents;
            return PartialView("_AgentsSidebar");
        }

        /// <summary>
        /// Calculates how much time it will take to run
        /// </summary>
        /// <param name="g">group</param>
        /// <param name="distribution"></param>
        /// <param name="enableSLM"></param>
        /// <param name="p">profile id's</param>
        /// <returns></returns>
        [HttpGet]
        public ContentResult UpdateTime(string g, string distribution, bool enableSLM, string p)
        {
            if (String.IsNullOrWhiteSpace(distribution) || String.IsNullOrWhiteSpace(p) || String.IsNullOrWhiteSpace(g)) return Content("N/A");

            var retVal = 0;
            var pDb = new Models.ProfilesEntities();
            var exeStat = new ExecutionStatisticsEntities();
            var profileIds = p.Split(',').Select(s => Int16.Parse(s.Trim())).ToList();

            if (profileIds.Count > 0)
            {
                foreach (var pId in profileIds)
                {
                    var profile = pDb.Profiles.ToList().Find(pid => pid.ProfileID == pId);
                    var stats = exeStat.ExecutionStatistics.Where(pn => pn.profileName == profile.ProfileName && pn.runtime > 25 && pn.runtime < 300).ToList();

                    if (enableSLM && stats.Count > 0)
                    {
                        retVal += (int)stats.Select(s => s.runtime).ToList().Average();
                    }
                    else
                    {
                        // ReSharper disable PossibleInvalidOperationException
                        retVal += profile.Weight.Value;
                        // ReSharper restore PossibleInvalidOperationException
                    }
                }

                if (distribution == "Even")
                {
                    var aCount = Shared.Common.GetAgentsList().Count(w => w.Group == g);

                    if (aCount > 0)
                        retVal = retVal/aCount;
                    else
                        retVal = 0;
                }
            }

            if (retVal > 0)
            {
                int minutes;
                var hours = Math.DivRem(retVal, 60, out minutes);

                return Content(string.Format("{0}h:{1}m", hours, minutes));
            }
            
            return Content("N/A");
        }
    }
}